Package Dependencies/ Data

Load Packages

First I need to load up the packages I’ll need

library(sf)
library(ggplot2) #development version!
## devtools::install_github("tidyverse/ggplot2")
library(tidyverse)
library(readr)
library(cowplot)
library(sp)
library(gridExtra)
library(dplyr)
library(ggrepel)
library(plyr)

Import Postcode Data

Now I import my data. I filter for the Arran postcodes, (since Arran all begins ‘KA27’).

#Add download commands for data.
## Finding the Arran coordinates
arrancoordinates <- read.csv("../alldata/ukpostcodes.csv") %>%
 filter(substr(postcode,1,4)=="KA27")
#Find way to replace with existing SIMD shape files
arransubsect <- read_sf("../alldata/Scotland_pcs_2011") %>%
filter(substr(label,1,4)=="KA27")

Import SIMD data

Now I load the SIMD data, containing the geometries (shapefiles) and SIMD data (percentiles, etc)

reorderedvector<- c("S01011174", "S01011171", "S01011177", "S01011176", "S01011175", "S01011173", "S01011172" )
arran2016 <- read_sf("../alldata/SG_SIMD_2016")[c(4672,4666,4669,4671,4667,4668,4670),] %>%
  slice(match(reorderedvector, DataZone))
Arrandz2012 <- c(4409,4372,4353,4352,4351,4350,4349)
arran2012 <- read_sf("../alldata/SG_SIMD_2012")[Arrandz2012,]
arran2009 <- read_sf("../alldata/SG_SIMD_2009")[Arrandz2012,]
arran2006 <- read_sf("../alldata/SG_SIMD_2006")[Arrandz2012,]
arran2004 <- read_sf("../alldata/SG_SIMD_2004")[Arrandz2012,]
sharedvariables <- intersect(colnames(arran2016), colnames(arran2012)) %>%
  intersect(colnames(arran2009))  %>%
  intersect(colnames(arran2006))  %>%
  intersect(colnames(arran2004))
  
arran20162 <- arran2016 %>%
  select(sharedvariables) %>%
  mutate(year="2016")
arran20122 <- arran2012 %>%
  select(sharedvariables) %>%
  mutate(year="2012")
arran20092 <- arran2009 %>%
  select(sharedvariables) %>%
  mutate(year="2009")
arran20062 <- arran2006 %>%
  select(sharedvariables) %>%
  mutate(year="2006")
arran20042 <- arran2004 %>%
  select(sharedvariables) %>%
  mutate(year="2004")
arransimd <- rbind(arran20162,arran20122,arran20092,arran20062,arran20042) %>%
mutate(
    lon = map_dbl(geometry, ~st_centroid(.x)[[1]]),
    lat = map_dbl(geometry, ~st_centroid(.x)[[2]])
    )
arransimd$listID <- revalue(arransimd$DataZone,
               c("S01004409"="S01004409/S01011174", "S01004372"="S01004372/S01011171", "S01004353"="S01004353/S01011177", "S01004352"="S01004352/S01011176", "S01004351"="S01004351/S01011175", "S01004350"="S01004350/S01011173", "S01004349"="S01004349/S01011172", "S01011174"="S01004409/S01011174", "S01011171"="S01004372/S01011171", "S01011177"="S01004353/S01011177", "S01011176"="S01004352/S01011176", "S01011175"="S01004351/S01011175", "S01011173"="S01004350/S01011173", "S01011172"="S01004349/S01011172"))

Now I want to overlay the postcodes by Datazone. To do this I’ve converted both the Arran coordinates and Arran (2016) shapefiles into spatial points/polygons, converted them into a common CRS, and then compared them by using ‘plyr::over()’. This gives me the object ‘namingdzpostcode’, with the postcode rows grouped into IDs (unidentified datazones).

simple.sf <- st_as_sf(arrancoordinates, coords=c('longitude','latitude'))
st_crs(simple.sf) <- 4326
exampleshapes <- sf:::as_Spatial(arran2016$geometry) %>%
  spTransform(CRS("+proj=longlat +datum=WGS84"))
examplepoints <- sf:::as_Spatial(simple.sf$geom) %>%
  spTransform(CRS("+proj=longlat +datum=WGS84"))
namingdzpostcode <- over(exampleshapes, examplepoints, returnList = TRUE)

I can then take a member reference from the orginal postcode list, which gives me a selection of the rows in that DZ. For simplicity I’ve written this as a new function. ##Mutate arrancoordinates to label the IDs

function100 <- function(argument) 
{
  argument <- arrancoordinates[namingdzpostcode[[argument]],] %>% mutate(DataZone=argument)
}
arrancoordinates <- lapply(1:7,function100)
arrancoordinates <- rbind(arrancoordinates[[1]], arrancoordinates[[2]], arrancoordinates[[3]], arrancoordinates[[4]], arrancoordinates[[5]], arrancoordinates[[6]], arrancoordinates[[7]])
arrancoordinates$listID <- revalue(as.character(arrancoordinates$DataZone),
               c('1'="S01004409/S01011174", '2'="S01004372/S01011171", '3'="S01004353/S01011177", '4'="S01004352/S01011176", '5'="S01004351/S01011175", '6'="S01004350/S01011173", '7'="S01004349/S01011172"))

Labelling the namingdzpostcode list

names(namingdzpostcode) <- c(unique(arransimd$listID))

//

Mapping

library(rgdal)
library(leaflet)
library(ggmap)

Coordinates

postcodelist <- paste(unique(arrancoordinates$listID), "Postcodes", sep=" ")
datazonelist <- paste(unique(arrancoordinates$listID), "Datazones", sep=" ")
m = leaflet() %>% addTiles() %>% setView(-5.227680, 55.582338, zoom = 10) 

Map1

m %>% 
#allcoordinates
addMarkers(
    lng = arrancoordinates$longitude, lat = arrancoordinates$latitude,
    label = arrancoordinates$postcode,
    labelOptions = labelOptions(noHide = F), group = "Postcode Plots") %>%
hideGroup("All Postcode Plots") %>% 
#alldatazones  
addPolygons(data=exampleshapes, 
            weight = 2, 
            label = datazonelist,
            group = "All Datazones") %>% 
hideGroup("Datazones") %>% 
  
#selectcoordinates
addMarkers(
    lng = arrancoordinates$longitude, lat = arrancoordinates$latitude,
    label = arrancoordinates$postcode,
    labelOptions = labelOptions(noHide = F), group = arrancoordinates$listID) %>% 
hideGroup(arrancoordinates$listID) %>% 
#selectdatazone
addPolygons(data = exampleshapes[1] , 
            weight = 2, label = datazonelist[1], group = datazonelist[1]) %>% 
addPolygons(data = exampleshapes[2] , 
            weight = 2, label = datazonelist[2], group = datazonelist[2]) %>% 
addPolygons(data = exampleshapes[3] , 
            weight = 2, label = datazonelist[3], group = datazonelist[3]) %>% 
addPolygons(data = exampleshapes[4] , 
            weight = 2, label = datazonelist[4], group = datazonelist[4]) %>% 
addPolygons(data = exampleshapes[5] , 
            weight = 2, label = datazonelist[5], group = datazonelist[5]) %>% 
addPolygons(data = exampleshapes[6] , 
            weight = 2, label = datazonelist[6], group = datazonelist[6]) %>% 
addPolygons(data = exampleshapes[7] , 
            weight = 2, label = datazonelist[7], group = datazonelist[7]) %>% 
hideGroup(datazonelist[1]) %>%
hideGroup(datazonelist[2]) %>%
hideGroup(datazonelist[3]) %>%
hideGroup(datazonelist[4]) %>%
hideGroup(datazonelist[5]) %>%
hideGroup(datazonelist[6]) %>%
hideGroup(datazonelist[7]) %>%
#Layers control
addLayersControl(
    baseGroups = c("All Datazones", "Postcode Plots", "Nothing"),
    overlayGroups = c(arrancoordinates$listID, datazonelist),
    options = layersControlOptions(collapsed = TRUE)
  )

Example Markers

Inputing example markers.

cliniccoordinates <- read.csv("../alldata/clinics.csv") %>%
dplyr::left_join(arrancoordinates, by="postcode")
Column `postcode` joining factors with different levels, coercing to character vector
#change to character
cliniccoordinates$X <- as.character(cliniccoordinates$X)

Map2

m %>%
#allcoordinates
addMarkers(
    lng = arrancoordinates$longitude, lat = arrancoordinates$latitude,
    label = arrancoordinates$postcode,
    labelOptions = labelOptions(noHide = F), group = "All Postcode Plots") %>%
hideGroup("All Postcode Plots") %>% 
#alldatazones  
addPolygons(data=exampleshapes, 
            weight = 2, 
            label = datazonelist,
            group = "All Datazones",
            highlightOptions = highlightOptions(color = "black", weight = 2,
      bringToFront = TRUE)) %>% 
hideGroup("All Datazones") %>% 
#cliniccoordinates
addMarkers(
    lng = cliniccoordinates$longitude, lat = cliniccoordinates$latitude,
    label = cliniccoordinates$X,
    labelOptions = labelOptions(noHide = F), group = "All GP clinics") %>%
  hideGroup("All GP clinics") %>%   
#cliniccoordinates
addMarkers(
    lng = cliniccoordinates$longitude, lat = cliniccoordinates$latitude,
    label = cliniccoordinates$X,
    labelOptions = labelOptions(noHide = F), group = cliniccoordinates$X) %>%
  hideGroup(cliniccoordinates$X) %>%   
  
#Layers control
addLayersControl(
    baseGroups = c("All Datazones", "All Postcode Plots", "All GP clinics", "Nothing"),
    overlayGroups = c(cliniccoordinates$X),
    options = layersControlOptions(collapsed = TRUE)
  )

Map3

Overlaying percentiles

exampleshapes2 <- as(arransimd, "Spatial") %>%
spTransform(CRS("+proj=longlat +datum=WGS84"))

Creating a palate for percentiles

pal2 <- colorNumeric(
  palette = "viridis",
  domain = exampleshapes2$Percentile)

Creating the percentile labels

listlistlist <- paste(datazonelist, exampleshapes2$Percentile, sep=" ") %>%
paste("%", sep="")

Map

m %>% 
#alldatazones  
addPolygons(data=exampleshapes2[exampleshapes2$year == 2004, ], 
            weight = 2, 
            label = listlistlist[29:35],
            group = "2004",
            fillOpacity =0.8,
            color = ~pal2(Percentile),
            highlightOptions = highlightOptions(color = "black", weight = 2,
      bringToFront = TRUE)) %>% 
hideGroup("2004") %>% 
  
addPolygons(data=exampleshapes2[exampleshapes2$year == 2006, ], 
            weight = 2, 
            label = listlistlist[22:28],
            group = "2006",
            fillOpacity =0.8,
            color = ~pal2(Percentile),
            highlightOptions = highlightOptions(color = "black", weight = 2,
      bringToFront = TRUE)) %>% 
hideGroup("2006") %>% 
  
addPolygons(data=exampleshapes2[exampleshapes2$year == 2009, ], 
            weight = 2, 
            label = listlistlist[15:21],
            group = "2009",
            fillOpacity =0.8,
            color = ~pal2(Percentile),
            highlightOptions = highlightOptions(color = "black", weight = 2,
      bringToFront = TRUE)) %>% 
hideGroup("2009") %>% 
  
addPolygons(data=exampleshapes2[exampleshapes2$year == 2012, ], 
            weight = 2, 
            label = listlistlist[8:14],
            group = "2012",
            fillOpacity =0.8,
            color = ~pal2(Percentile),
            highlightOptions = highlightOptions(color = "black", weight = 2,
      bringToFront = TRUE)) %>% 
hideGroup("2012") %>% 
addPolygons(data=exampleshapes2[exampleshapes2$year == 2016, ], 
            weight = 2, 
            label = listlistlist[1:7],
            group = "2016",
            fillOpacity =0.8,
            color = ~pal2(Percentile),
            highlightOptions = highlightOptions(color = "black", weight = 2,
      bringToFront = TRUE)) %>% 
hideGroup("2016") %>% 
  
#cliniccoordinates
addMarkers(
    lng = cliniccoordinates$longitude, lat = cliniccoordinates$latitude,
    label = cliniccoordinates$X,
    labelOptions = labelOptions(noHide = F), group = cliniccoordinates$X) %>%
  hideGroup(cliniccoordinates$X) %>%   
addLegend("bottomleft", pal = pal2, values = exampleshapes2$Percentile,
    title = "SIMD Percentile",
    labFormat = labelFormat(suffix = "%"),
    opacity = 1
  )  %>%  
#Layers control
addLayersControl(
    baseGroups = c("2004", "2006", "2009", "2012", "2016", "Nothing"),
    overlayGroups = c(cliniccoordinates$X),
    options = layersControlOptions(collapsed = TRUE)
  )

Map4 Arran vs. Scotland

Beautiful map, but I have to leave the laptop running overnight to compile it.

#Import UK data
DZBoundaries2016 <- read_sf("../alldata/SG_SIMD_2016")
Scotland2016 <- as(DZBoundaries2016, "Spatial") %>%
spTransform(CRS("+proj=longlat +datum=WGS84"))

DZBoundaries2012 <- read_sf("../alldata/SG_SIMD_2012")
Scotland2012 <- as(DZBoundaries2012, "Spatial") %>%
spTransform(CRS("+proj=longlat +datum=WGS84"))

DZBoundaries2009 <- read_sf("../alldata/SG_SIMD_2009")
Scotland2009 <- as(DZBoundaries2009, "Spatial") %>%
spTransform(CRS("+proj=longlat +datum=WGS84"))

DZBoundaries2006 <- read_sf("../alldata/SG_SIMD_2006")
Scotland2006 <- as(DZBoundaries2006, "Spatial") %>%
spTransform(CRS("+proj=longlat +datum=WGS84"))

DZBoundaries2004 <- read_sf("../alldata/SG_SIMD_2004")
Scotland2004 <- as(DZBoundaries2004, "Spatial") %>%
spTransform(CRS("+proj=longlat +datum=WGS84"))

#Colour Palate
pal2 <- colorNumeric(
  palette = "viridis",
  domain = 0:100)

leaflet() %>% 
  addTiles() %>% 
  setView(-5.227680, 55.582338, zoom = 10) %>% 

addPolygons(data=exampleshapes2[exampleshapes2$year == 2004, ], 
            weight = 2, 
            label = listlistlist[29:35],
            group = "2004",
            fillOpacity =0.8,
            color = ~pal2(Percentile),
            highlightOptions = highlightOptions(color = "black", weight = 2,
      bringToFront = TRUE)) %>% 
hideGroup("2004") %>% 
  
addPolygons(data=Scotland2004, 
            weight = 2, 
            group = "Scotland 2004",
            fillOpacity =0.8,
            color = ~pal2(Percentile),
            highlightOptions = highlightOptions(color = "black", weight = 2,
      bringToFront = TRUE)) %>% 
hideGroup("Scotland 2004") %>% 
  
addPolygons(data=exampleshapes2[exampleshapes2$year == 2006, ], 
            weight = 2, 
            label = listlistlist[22:28],
            group = "2006",
            fillOpacity =0.8,
            color = ~pal2(Percentile),
            highlightOptions = highlightOptions(color = "black", weight = 2,
      bringToFront = TRUE)) %>% 
hideGroup("2006") %>% 

addPolygons(data=Scotland2006, 
            weight = 2, 
            group = "Scotland 2006",
            fillOpacity =0.8,
            color = ~pal2(Percentile),
            highlightOptions = highlightOptions(color = "black", weight = 2,
      bringToFront = TRUE)) %>% 
hideGroup("Scotland 2006") %>% 
  
addPolygons(data=exampleshapes2[exampleshapes2$year == 2009, ], 
            weight = 2, 
            label = listlistlist[15:21],
            group = "2009",
            fillOpacity =0.8,
            color = ~pal2(Percentile),
            highlightOptions = highlightOptions(color = "black", weight = 2,
      bringToFront = TRUE)) %>% 
hideGroup("2009") %>% 

addPolygons(data=Scotland2009, 
            weight = 2, 
            group = "Scotland 2009",
            fillOpacity =0.8,
            color = ~pal2(Percentile),
            highlightOptions = highlightOptions(color = "black", weight = 2,
      bringToFront = TRUE)) %>% 
hideGroup("Scotland 2009") %>% 
  
addPolygons(data=exampleshapes2[exampleshapes2$year == 2012, ], 
            weight = 2, 
            label = listlistlist[8:14],
            group = "2012",
            fillOpacity =0.8,
            color = ~pal2(Percentile),
            highlightOptions = highlightOptions(color = "black", weight = 2,
      bringToFront = TRUE)) %>% 
hideGroup("2012") %>% 
  
addPolygons(data=Scotland2012, 
            weight = 2, 
            group = "Scotland 2012",
            fillOpacity =0.8,
            color = ~pal2(Percentile),
            highlightOptions = highlightOptions(color = "black", weight = 2,
      bringToFront = TRUE)) %>% 
hideGroup("Scotland 2012") %>% 

addPolygons(data=exampleshapes2[exampleshapes2$year == 2016, ], 
            weight = 2, 
            label = listlistlist[1:7],
            group = "2016",
            fillOpacity =0.8,
            color = ~pal2(Percentile),
            highlightOptions = highlightOptions(color = "black", weight = 2,
      bringToFront = TRUE)) %>% 
hideGroup("2016") %>% 

addPolygons(data=Scotland2012, 
            weight = 2, 
            group = "Scotland 2016",
            fillOpacity =0.8,
            color = ~pal2(Percentile),
            highlightOptions = highlightOptions(color = "black", weight = 2,
      bringToFront = TRUE)) %>% 
hideGroup("Scotland 2016") %>% 
  
addMarkers(
    lng = cliniccoordinates$longitude, lat = cliniccoordinates$latitude,
    label = cliniccoordinates$X,
    labelOptions = labelOptions(noHide = F), group = cliniccoordinates$X) %>%
  hideGroup(cliniccoordinates$X) %>%   

addLegend("bottomleft", pal = pal2, values = exampleshapes2$Percentile,
    title = "SIMD Percentile",
    labFormat = labelFormat(suffix = "%"),
    opacity = 1
  )  %>%  

addLayersControl(
    baseGroups = c("2004", "Scotland 2004", "2006", "Scotland 2006", "2009", "Scotland 2009", "2012", "Scotland 2012", "2016", "Scotland 2016", "Nothing"),
    overlayGroups = c(cliniccoordinates$X),
    options = layersControlOptions(collapsed = TRUE)
  )
Map4

Map4

Map5

I’ll continue this on a new document so I can knit it to an html website.

Map5.

Map5 Code.

But the development is that I’ve used intersect() on each filtered ‘SG_SIMD_…’ to create the ‘sharedvariables’ vector, so I was able to create a new dataframe of every year with only shared variables, rather than percentile alone which I originally used as an example to practice the maps on (my previous version of ‘arransimd’). The new ‘arranSIMD’ can then have a version of map3 for each shared variable.

Go back.

LS0tCnRpdGxlOiAiTWFwIENvZGUiCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgdG9jOiB5ZXMKICAgIHRvY19mbG9hdDogeWVzCiAgaHRtbF9ub3RlYm9vazogZGVmYXVsdAotLS0KI1BhY2thZ2UgRGVwZW5kZW5jaWVzLyBEYXRhCiMjTG9hZCBQYWNrYWdlcwpGaXJzdCBJIG5lZWQgdG8gbG9hZCB1cCB0aGUgcGFja2FnZXMgSSdsbCBuZWVkCmBgYHtyfQpsaWJyYXJ5KHNmKQpsaWJyYXJ5KGdncGxvdDIpICNkZXZlbG9wbWVudCB2ZXJzaW9uIQojIyBkZXZ0b29sczo6aW5zdGFsbF9naXRodWIoInRpZHl2ZXJzZS9nZ3Bsb3QyIikKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkocmVhZHIpCmxpYnJhcnkoY293cGxvdCkKbGlicmFyeShzcCkKbGlicmFyeShncmlkRXh0cmEpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoZ2dyZXBlbCkKbGlicmFyeShwbHlyKQpgYGAKCiMjSW1wb3J0IFBvc3Rjb2RlIERhdGEKTm93IEkgaW1wb3J0IG15IGRhdGEuIEkgZmlsdGVyIGZvciB0aGUgQXJyYW4gcG9zdGNvZGVzLCAoc2luY2UgQXJyYW4gYWxsIGJlZ2lucyAnS0EyNycpLgpgYGB7cn0KI0FkZCBkb3dubG9hZCBjb21tYW5kcyBmb3IgZGF0YS4KIyMgRmluZGluZyB0aGUgQXJyYW4gY29vcmRpbmF0ZXMKYXJyYW5jb29yZGluYXRlcyA8LSByZWFkLmNzdigiLi4vYWxsZGF0YS91a3Bvc3Rjb2Rlcy5jc3YiKSAlPiUKIGZpbHRlcihzdWJzdHIocG9zdGNvZGUsMSw0KT09IktBMjciKQoKI0ZpbmQgd2F5IHRvIHJlcGxhY2Ugd2l0aCBleGlzdGluZyBTSU1EIHNoYXBlIGZpbGVzCmFycmFuc3Vic2VjdCA8LSByZWFkX3NmKCIuLi9hbGxkYXRhL1Njb3RsYW5kX3Bjc18yMDExIikgJT4lCmZpbHRlcihzdWJzdHIobGFiZWwsMSw0KT09IktBMjciKQpgYGAKCiMjSW1wb3J0IFNJTUQgZGF0YQpOb3cgSSBsb2FkIHRoZSBTSU1EIGRhdGEsIGNvbnRhaW5pbmcgdGhlIGdlb21ldHJpZXMgKHNoYXBlZmlsZXMpIGFuZCBTSU1EIGRhdGEgKHBlcmNlbnRpbGVzLCBldGMpCmBgYHtyfQpyZW9yZGVyZWR2ZWN0b3I8LSBjKCJTMDEwMTExNzQiLCAiUzAxMDExMTcxIiwgIlMwMTAxMTE3NyIsICJTMDEwMTExNzYiLCAiUzAxMDExMTc1IiwgIlMwMTAxMTE3MyIsICJTMDEwMTExNzIiICkKCmFycmFuMjAxNiA8LSByZWFkX3NmKCIuLi9hbGxkYXRhL1NHX1NJTURfMjAxNiIpW2MoNDY3Miw0NjY2LDQ2NjksNDY3MSw0NjY3LDQ2NjgsNDY3MCksXSAlPiUKICBzbGljZShtYXRjaChyZW9yZGVyZWR2ZWN0b3IsIERhdGFab25lKSkKCkFycmFuZHoyMDEyIDwtIGMoNDQwOSw0MzcyLDQzNTMsNDM1Miw0MzUxLDQzNTAsNDM0OSkKCmFycmFuMjAxMiA8LSByZWFkX3NmKCIuLi9hbGxkYXRhL1NHX1NJTURfMjAxMiIpW0FycmFuZHoyMDEyLF0KYXJyYW4yMDA5IDwtIHJlYWRfc2YoIi4uL2FsbGRhdGEvU0dfU0lNRF8yMDA5IilbQXJyYW5kejIwMTIsXQphcnJhbjIwMDYgPC0gcmVhZF9zZigiLi4vYWxsZGF0YS9TR19TSU1EXzIwMDYiKVtBcnJhbmR6MjAxMixdCmFycmFuMjAwNCA8LSByZWFkX3NmKCIuLi9hbGxkYXRhL1NHX1NJTURfMjAwNCIpW0FycmFuZHoyMDEyLF0KCnNoYXJlZHZhcmlhYmxlcyA8LSBpbnRlcnNlY3QoY29sbmFtZXMoYXJyYW4yMDE2KSwgY29sbmFtZXMoYXJyYW4yMDEyKSkgJT4lCiAgaW50ZXJzZWN0KGNvbG5hbWVzKGFycmFuMjAwOSkpICAlPiUKICBpbnRlcnNlY3QoY29sbmFtZXMoYXJyYW4yMDA2KSkgICU+JQogIGludGVyc2VjdChjb2xuYW1lcyhhcnJhbjIwMDQpKQogIAphcnJhbjIwMTYyIDwtIGFycmFuMjAxNiAlPiUKICBzZWxlY3Qoc2hhcmVkdmFyaWFibGVzKSAlPiUKICBtdXRhdGUoeWVhcj0iMjAxNiIpCmFycmFuMjAxMjIgPC0gYXJyYW4yMDEyICU+JQogIHNlbGVjdChzaGFyZWR2YXJpYWJsZXMpICU+JQogIG11dGF0ZSh5ZWFyPSIyMDEyIikKYXJyYW4yMDA5MiA8LSBhcnJhbjIwMDkgJT4lCiAgc2VsZWN0KHNoYXJlZHZhcmlhYmxlcykgJT4lCiAgbXV0YXRlKHllYXI9IjIwMDkiKQphcnJhbjIwMDYyIDwtIGFycmFuMjAwNiAlPiUKICBzZWxlY3Qoc2hhcmVkdmFyaWFibGVzKSAlPiUKICBtdXRhdGUoeWVhcj0iMjAwNiIpCmFycmFuMjAwNDIgPC0gYXJyYW4yMDA0ICU+JQogIHNlbGVjdChzaGFyZWR2YXJpYWJsZXMpICU+JQogIG11dGF0ZSh5ZWFyPSIyMDA0IikKCmFycmFuc2ltZCA8LSByYmluZChhcnJhbjIwMTYyLGFycmFuMjAxMjIsYXJyYW4yMDA5MixhcnJhbjIwMDYyLGFycmFuMjAwNDIpICU+JQptdXRhdGUoCiAgICBsb24gPSBtYXBfZGJsKGdlb21ldHJ5LCB+c3RfY2VudHJvaWQoLngpW1sxXV0pLAogICAgbGF0ID0gbWFwX2RibChnZW9tZXRyeSwgfnN0X2NlbnRyb2lkKC54KVtbMl1dKQogICAgKQoKYXJyYW5zaW1kJGxpc3RJRCA8LSByZXZhbHVlKGFycmFuc2ltZCREYXRhWm9uZSwKICAgICAgICAgICAgICAgYygiUzAxMDA0NDA5Ij0iUzAxMDA0NDA5L1MwMTAxMTE3NCIsICJTMDEwMDQzNzIiPSJTMDEwMDQzNzIvUzAxMDExMTcxIiwgIlMwMTAwNDM1MyI9IlMwMTAwNDM1My9TMDEwMTExNzciLCAiUzAxMDA0MzUyIj0iUzAxMDA0MzUyL1MwMTAxMTE3NiIsICJTMDEwMDQzNTEiPSJTMDEwMDQzNTEvUzAxMDExMTc1IiwgIlMwMTAwNDM1MCI9IlMwMTAwNDM1MC9TMDEwMTExNzMiLCAiUzAxMDA0MzQ5Ij0iUzAxMDA0MzQ5L1MwMTAxMTE3MiIsICJTMDEwMTExNzQiPSJTMDEwMDQ0MDkvUzAxMDExMTc0IiwgIlMwMTAxMTE3MSI9IlMwMTAwNDM3Mi9TMDEwMTExNzEiLCAiUzAxMDExMTc3Ij0iUzAxMDA0MzUzL1MwMTAxMTE3NyIsICJTMDEwMTExNzYiPSJTMDEwMDQzNTIvUzAxMDExMTc2IiwgIlMwMTAxMTE3NSI9IlMwMTAwNDM1MS9TMDEwMTExNzUiLCAiUzAxMDExMTczIj0iUzAxMDA0MzUwL1MwMTAxMTE3MyIsICJTMDEwMTExNzIiPSJTMDEwMDQzNDkvUzAxMDExMTcyIikpCmBgYAoKTm93IEkgd2FudCB0byBvdmVybGF5IHRoZSBwb3N0Y29kZXMgYnkgRGF0YXpvbmUuClRvIGRvIHRoaXMgSSd2ZSBjb252ZXJ0ZWQgYm90aCB0aGUgQXJyYW4gY29vcmRpbmF0ZXMgYW5kIEFycmFuICgyMDE2KSBzaGFwZWZpbGVzIGludG8gc3BhdGlhbCBwb2ludHMvcG9seWdvbnMsIGNvbnZlcnRlZCB0aGVtIGludG8gYSBjb21tb24gQ1JTLCBhbmQgdGhlbiBjb21wYXJlZCB0aGVtIGJ5IHVzaW5nICdwbHlyOjpvdmVyKCknLgpUaGlzIGdpdmVzIG1lIHRoZSBvYmplY3QgJ25hbWluZ2R6cG9zdGNvZGUnLCB3aXRoIHRoZSBwb3N0Y29kZSByb3dzIGdyb3VwZWQgaW50byBJRHMgKHVuaWRlbnRpZmllZCBkYXRhem9uZXMpLgpgYGB7cn0Kc2ltcGxlLnNmIDwtIHN0X2FzX3NmKGFycmFuY29vcmRpbmF0ZXMsIGNvb3Jkcz1jKCdsb25naXR1ZGUnLCdsYXRpdHVkZScpKQpzdF9jcnMoc2ltcGxlLnNmKSA8LSA0MzI2CgpleGFtcGxlc2hhcGVzIDwtIHNmOjo6YXNfU3BhdGlhbChhcnJhbjIwMTYkZ2VvbWV0cnkpICU+JQogIHNwVHJhbnNmb3JtKENSUygiK3Byb2o9bG9uZ2xhdCArZGF0dW09V0dTODQiKSkKCmV4YW1wbGVwb2ludHMgPC0gc2Y6Ojphc19TcGF0aWFsKHNpbXBsZS5zZiRnZW9tKSAlPiUKICBzcFRyYW5zZm9ybShDUlMoIitwcm9qPWxvbmdsYXQgK2RhdHVtPVdHUzg0IikpCgpuYW1pbmdkenBvc3Rjb2RlIDwtIG92ZXIoZXhhbXBsZXNoYXBlcywgZXhhbXBsZXBvaW50cywgcmV0dXJuTGlzdCA9IFRSVUUpCmBgYAoKSSBjYW4gdGhlbiB0YWtlIGEgbWVtYmVyIHJlZmVyZW5jZSBmcm9tIHRoZSBvcmdpbmFsIHBvc3Rjb2RlIGxpc3QsIHdoaWNoIGdpdmVzIG1lIGEgc2VsZWN0aW9uIG9mIHRoZSByb3dzIGluIHRoYXQgRFouIEZvciBzaW1wbGljaXR5IEkndmUgd3JpdHRlbiB0aGlzIGFzIGEgbmV3IGZ1bmN0aW9uLiAKIyNNdXRhdGUgYXJyYW5jb29yZGluYXRlcyB0byBsYWJlbCB0aGUgSURzCmBgYHtyfQpmdW5jdGlvbjEwMCA8LSBmdW5jdGlvbihhcmd1bWVudCkgCnsKICBhcmd1bWVudCA8LSBhcnJhbmNvb3JkaW5hdGVzW25hbWluZ2R6cG9zdGNvZGVbW2FyZ3VtZW50XV0sXSAlPiUgbXV0YXRlKERhdGFab25lPWFyZ3VtZW50KQp9CgphcnJhbmNvb3JkaW5hdGVzIDwtIGxhcHBseSgxOjcsZnVuY3Rpb24xMDApCmFycmFuY29vcmRpbmF0ZXMgPC0gcmJpbmQoYXJyYW5jb29yZGluYXRlc1tbMV1dLCBhcnJhbmNvb3JkaW5hdGVzW1syXV0sIGFycmFuY29vcmRpbmF0ZXNbWzNdXSwgYXJyYW5jb29yZGluYXRlc1tbNF1dLCBhcnJhbmNvb3JkaW5hdGVzW1s1XV0sIGFycmFuY29vcmRpbmF0ZXNbWzZdXSwgYXJyYW5jb29yZGluYXRlc1tbN11dKQoKYXJyYW5jb29yZGluYXRlcyRsaXN0SUQgPC0gcmV2YWx1ZShhcy5jaGFyYWN0ZXIoYXJyYW5jb29yZGluYXRlcyREYXRhWm9uZSksCiAgICAgICAgICAgICAgIGMoJzEnPSJTMDEwMDQ0MDkvUzAxMDExMTc0IiwgJzInPSJTMDEwMDQzNzIvUzAxMDExMTcxIiwgJzMnPSJTMDEwMDQzNTMvUzAxMDExMTc3IiwgJzQnPSJTMDEwMDQzNTIvUzAxMDExMTc2IiwgJzUnPSJTMDEwMDQzNTEvUzAxMDExMTc1IiwgJzYnPSJTMDEwMDQzNTAvUzAxMDExMTczIiwgJzcnPSJTMDEwMDQzNDkvUzAxMDExMTcyIikpCmBgYAoKIyNMYWJlbGxpbmcgdGhlIG5hbWluZ2R6cG9zdGNvZGUgbGlzdApgYGB7cn0KbmFtZXMobmFtaW5nZHpwb3N0Y29kZSkgPC0gYyh1bmlxdWUoYXJyYW5zaW1kJGxpc3RJRCkpCmBgYAoKLy8KCiNNYXBwaW5nCmBgYHtyfQpsaWJyYXJ5KHJnZGFsKQpsaWJyYXJ5KGxlYWZsZXQpCmxpYnJhcnkoZ2dtYXApCmBgYAoKIyNDb29yZGluYXRlcwpgYGB7cn0KcG9zdGNvZGVsaXN0IDwtIHBhc3RlKHVuaXF1ZShhcnJhbmNvb3JkaW5hdGVzJGxpc3RJRCksICJQb3N0Y29kZXMiLCBzZXA9IiAiKQpkYXRhem9uZWxpc3QgPC0gcGFzdGUodW5pcXVlKGFycmFuY29vcmRpbmF0ZXMkbGlzdElEKSwgIkRhdGF6b25lcyIsIHNlcD0iICIpCgptID0gbGVhZmxldCgpICU+JSBhZGRUaWxlcygpICU+JSBzZXRWaWV3KC01LjIyNzY4MCwgNTUuNTgyMzM4LCB6b29tID0gMTApIApgYGAKCiNNYXAxCmBgYHtyfQptICU+JSAKCiNhbGxjb29yZGluYXRlcwphZGRNYXJrZXJzKAogICAgbG5nID0gYXJyYW5jb29yZGluYXRlcyRsb25naXR1ZGUsIGxhdCA9IGFycmFuY29vcmRpbmF0ZXMkbGF0aXR1ZGUsCiAgICBsYWJlbCA9IGFycmFuY29vcmRpbmF0ZXMkcG9zdGNvZGUsCiAgICBsYWJlbE9wdGlvbnMgPSBsYWJlbE9wdGlvbnMobm9IaWRlID0gRiksIGdyb3VwID0gIlBvc3Rjb2RlIFBsb3RzIikgJT4lCmhpZGVHcm91cCgiQWxsIFBvc3Rjb2RlIFBsb3RzIikgJT4lIAoKI2FsbGRhdGF6b25lcyAgCmFkZFBvbHlnb25zKGRhdGE9ZXhhbXBsZXNoYXBlcywgCiAgICAgICAgICAgIHdlaWdodCA9IDIsIAogICAgICAgICAgICBsYWJlbCA9IGRhdGF6b25lbGlzdCwKICAgICAgICAgICAgZ3JvdXAgPSAiQWxsIERhdGF6b25lcyIpICU+JSAKaGlkZUdyb3VwKCJEYXRhem9uZXMiKSAlPiUgCiAgCiNzZWxlY3Rjb29yZGluYXRlcwphZGRNYXJrZXJzKAogICAgbG5nID0gYXJyYW5jb29yZGluYXRlcyRsb25naXR1ZGUsIGxhdCA9IGFycmFuY29vcmRpbmF0ZXMkbGF0aXR1ZGUsCiAgICBsYWJlbCA9IGFycmFuY29vcmRpbmF0ZXMkcG9zdGNvZGUsCiAgICBsYWJlbE9wdGlvbnMgPSBsYWJlbE9wdGlvbnMobm9IaWRlID0gRiksIGdyb3VwID0gYXJyYW5jb29yZGluYXRlcyRsaXN0SUQpICU+JSAKaGlkZUdyb3VwKGFycmFuY29vcmRpbmF0ZXMkbGlzdElEKSAlPiUgCgojc2VsZWN0ZGF0YXpvbmUKYWRkUG9seWdvbnMoZGF0YSA9IGV4YW1wbGVzaGFwZXNbMV0gLCAKICAgICAgICAgICAgd2VpZ2h0ID0gMiwgbGFiZWwgPSBkYXRhem9uZWxpc3RbMV0sIGdyb3VwID0gZGF0YXpvbmVsaXN0WzFdKSAlPiUgCmFkZFBvbHlnb25zKGRhdGEgPSBleGFtcGxlc2hhcGVzWzJdICwgCiAgICAgICAgICAgIHdlaWdodCA9IDIsIGxhYmVsID0gZGF0YXpvbmVsaXN0WzJdLCBncm91cCA9IGRhdGF6b25lbGlzdFsyXSkgJT4lIAphZGRQb2x5Z29ucyhkYXRhID0gZXhhbXBsZXNoYXBlc1szXSAsIAogICAgICAgICAgICB3ZWlnaHQgPSAyLCBsYWJlbCA9IGRhdGF6b25lbGlzdFszXSwgZ3JvdXAgPSBkYXRhem9uZWxpc3RbM10pICU+JSAKYWRkUG9seWdvbnMoZGF0YSA9IGV4YW1wbGVzaGFwZXNbNF0gLCAKICAgICAgICAgICAgd2VpZ2h0ID0gMiwgbGFiZWwgPSBkYXRhem9uZWxpc3RbNF0sIGdyb3VwID0gZGF0YXpvbmVsaXN0WzRdKSAlPiUgCmFkZFBvbHlnb25zKGRhdGEgPSBleGFtcGxlc2hhcGVzWzVdICwgCiAgICAgICAgICAgIHdlaWdodCA9IDIsIGxhYmVsID0gZGF0YXpvbmVsaXN0WzVdLCBncm91cCA9IGRhdGF6b25lbGlzdFs1XSkgJT4lIAphZGRQb2x5Z29ucyhkYXRhID0gZXhhbXBsZXNoYXBlc1s2XSAsIAogICAgICAgICAgICB3ZWlnaHQgPSAyLCBsYWJlbCA9IGRhdGF6b25lbGlzdFs2XSwgZ3JvdXAgPSBkYXRhem9uZWxpc3RbNl0pICU+JSAKYWRkUG9seWdvbnMoZGF0YSA9IGV4YW1wbGVzaGFwZXNbN10gLCAKICAgICAgICAgICAgd2VpZ2h0ID0gMiwgbGFiZWwgPSBkYXRhem9uZWxpc3RbN10sIGdyb3VwID0gZGF0YXpvbmVsaXN0WzddKSAlPiUgCmhpZGVHcm91cChkYXRhem9uZWxpc3RbMV0pICU+JQpoaWRlR3JvdXAoZGF0YXpvbmVsaXN0WzJdKSAlPiUKaGlkZUdyb3VwKGRhdGF6b25lbGlzdFszXSkgJT4lCmhpZGVHcm91cChkYXRhem9uZWxpc3RbNF0pICU+JQpoaWRlR3JvdXAoZGF0YXpvbmVsaXN0WzVdKSAlPiUKaGlkZUdyb3VwKGRhdGF6b25lbGlzdFs2XSkgJT4lCmhpZGVHcm91cChkYXRhem9uZWxpc3RbN10pICU+JQoKI0xheWVycyBjb250cm9sCmFkZExheWVyc0NvbnRyb2woCiAgICBiYXNlR3JvdXBzID0gYygiQWxsIERhdGF6b25lcyIsICJQb3N0Y29kZSBQbG90cyIsICJOb3RoaW5nIiksCiAgICBvdmVybGF5R3JvdXBzID0gYyhhcnJhbmNvb3JkaW5hdGVzJGxpc3RJRCwgZGF0YXpvbmVsaXN0KSwKICAgIG9wdGlvbnMgPSBsYXllcnNDb250cm9sT3B0aW9ucyhjb2xsYXBzZWQgPSBUUlVFKQogICkKYGBgCgojRXhhbXBsZSBNYXJrZXJzCklucHV0aW5nIGV4YW1wbGUgbWFya2Vycy4KYGBge3J9CmNsaW5pY2Nvb3JkaW5hdGVzIDwtIHJlYWQuY3N2KCIuLi9hbGxkYXRhL2NsaW5pY3MuY3N2IikgJT4lCmRwbHlyOjpsZWZ0X2pvaW4oYXJyYW5jb29yZGluYXRlcywgYnk9InBvc3Rjb2RlIikKI2NoYW5nZSB0byBjaGFyYWN0ZXIKY2xpbmljY29vcmRpbmF0ZXMkWCA8LSBhcy5jaGFyYWN0ZXIoY2xpbmljY29vcmRpbmF0ZXMkWCkKYGBgCgojTWFwMgpgYGB7cn0KbSAlPiUKCiNhbGxjb29yZGluYXRlcwphZGRNYXJrZXJzKAogICAgbG5nID0gYXJyYW5jb29yZGluYXRlcyRsb25naXR1ZGUsIGxhdCA9IGFycmFuY29vcmRpbmF0ZXMkbGF0aXR1ZGUsCiAgICBsYWJlbCA9IGFycmFuY29vcmRpbmF0ZXMkcG9zdGNvZGUsCiAgICBsYWJlbE9wdGlvbnMgPSBsYWJlbE9wdGlvbnMobm9IaWRlID0gRiksIGdyb3VwID0gIkFsbCBQb3N0Y29kZSBQbG90cyIpICU+JQpoaWRlR3JvdXAoIkFsbCBQb3N0Y29kZSBQbG90cyIpICU+JSAKCiNhbGxkYXRhem9uZXMgIAphZGRQb2x5Z29ucyhkYXRhPWV4YW1wbGVzaGFwZXMsIAogICAgICAgICAgICB3ZWlnaHQgPSAyLCAKICAgICAgICAgICAgbGFiZWwgPSBkYXRhem9uZWxpc3QsCiAgICAgICAgICAgIGdyb3VwID0gIkFsbCBEYXRhem9uZXMiLAogICAgICAgICAgICBoaWdobGlnaHRPcHRpb25zID0gaGlnaGxpZ2h0T3B0aW9ucyhjb2xvciA9ICJibGFjayIsIHdlaWdodCA9IDIsCiAgICAgIGJyaW5nVG9Gcm9udCA9IFRSVUUpKSAlPiUgCmhpZGVHcm91cCgiQWxsIERhdGF6b25lcyIpICU+JSAKCiNjbGluaWNjb29yZGluYXRlcwphZGRNYXJrZXJzKAogICAgbG5nID0gY2xpbmljY29vcmRpbmF0ZXMkbG9uZ2l0dWRlLCBsYXQgPSBjbGluaWNjb29yZGluYXRlcyRsYXRpdHVkZSwKICAgIGxhYmVsID0gY2xpbmljY29vcmRpbmF0ZXMkWCwKICAgIGxhYmVsT3B0aW9ucyA9IGxhYmVsT3B0aW9ucyhub0hpZGUgPSBGKSwgZ3JvdXAgPSAiQWxsIEdQIGNsaW5pY3MiKSAlPiUKICBoaWRlR3JvdXAoIkFsbCBHUCBjbGluaWNzIikgJT4lICAgCgojY2xpbmljY29vcmRpbmF0ZXMKYWRkTWFya2VycygKICAgIGxuZyA9IGNsaW5pY2Nvb3JkaW5hdGVzJGxvbmdpdHVkZSwgbGF0ID0gY2xpbmljY29vcmRpbmF0ZXMkbGF0aXR1ZGUsCiAgICBsYWJlbCA9IGNsaW5pY2Nvb3JkaW5hdGVzJFgsCiAgICBsYWJlbE9wdGlvbnMgPSBsYWJlbE9wdGlvbnMobm9IaWRlID0gRiksIGdyb3VwID0gY2xpbmljY29vcmRpbmF0ZXMkWCkgJT4lCiAgaGlkZUdyb3VwKGNsaW5pY2Nvb3JkaW5hdGVzJFgpICU+JSAgIAogIAojTGF5ZXJzIGNvbnRyb2wKYWRkTGF5ZXJzQ29udHJvbCgKICAgIGJhc2VHcm91cHMgPSBjKCJBbGwgRGF0YXpvbmVzIiwgIkFsbCBQb3N0Y29kZSBQbG90cyIsICJBbGwgR1AgY2xpbmljcyIsICJOb3RoaW5nIiksCiAgICBvdmVybGF5R3JvdXBzID0gYyhjbGluaWNjb29yZGluYXRlcyRYKSwKICAgIG9wdGlvbnMgPSBsYXllcnNDb250cm9sT3B0aW9ucyhjb2xsYXBzZWQgPSBUUlVFKQogICkKYGBgCgojTWFwMwojI092ZXJsYXlpbmcgcGVyY2VudGlsZXMKYGBge3J9CmV4YW1wbGVzaGFwZXMyIDwtIGFzKGFycmFuc2ltZCwgIlNwYXRpYWwiKSAlPiUKc3BUcmFuc2Zvcm0oQ1JTKCIrcHJvaj1sb25nbGF0ICtkYXR1bT1XR1M4NCIpKQpgYGAKCiMjQ3JlYXRpbmcgYSBwYWxhdGUgZm9yIHBlcmNlbnRpbGVzCmBgYHtyfQpwYWwyIDwtIGNvbG9yTnVtZXJpYygKICBwYWxldHRlID0gInZpcmlkaXMiLAogIGRvbWFpbiA9IGV4YW1wbGVzaGFwZXMyJFBlcmNlbnRpbGUpCmBgYAoKIyNDcmVhdGluZyB0aGUgcGVyY2VudGlsZSBsYWJlbHMKYGBge3J9Cmxpc3RsaXN0bGlzdCA8LSBwYXN0ZShkYXRhem9uZWxpc3QsIGV4YW1wbGVzaGFwZXMyJFBlcmNlbnRpbGUsIHNlcD0iICIpICU+JQpwYXN0ZSgiJSIsIHNlcD0iIikKYGBgCgojI01hcApgYGB7cn0KbSAlPiUgCgojYWxsZGF0YXpvbmVzICAKYWRkUG9seWdvbnMoZGF0YT1leGFtcGxlc2hhcGVzMltleGFtcGxlc2hhcGVzMiR5ZWFyID09IDIwMDQsIF0sIAogICAgICAgICAgICB3ZWlnaHQgPSAyLCAKICAgICAgICAgICAgbGFiZWwgPSBsaXN0bGlzdGxpc3RbMjk6MzVdLAogICAgICAgICAgICBncm91cCA9ICIyMDA0IiwKICAgICAgICAgICAgZmlsbE9wYWNpdHkgPTAuOCwKICAgICAgICAgICAgY29sb3IgPSB+cGFsMihQZXJjZW50aWxlKSwKICAgICAgICAgICAgaGlnaGxpZ2h0T3B0aW9ucyA9IGhpZ2hsaWdodE9wdGlvbnMoY29sb3IgPSAiYmxhY2siLCB3ZWlnaHQgPSAyLAogICAgICBicmluZ1RvRnJvbnQgPSBUUlVFKSkgJT4lIApoaWRlR3JvdXAoIjIwMDQiKSAlPiUgCiAgCmFkZFBvbHlnb25zKGRhdGE9ZXhhbXBsZXNoYXBlczJbZXhhbXBsZXNoYXBlczIkeWVhciA9PSAyMDA2LCBdLCAKICAgICAgICAgICAgd2VpZ2h0ID0gMiwgCiAgICAgICAgICAgIGxhYmVsID0gbGlzdGxpc3RsaXN0WzIyOjI4XSwKICAgICAgICAgICAgZ3JvdXAgPSAiMjAwNiIsCiAgICAgICAgICAgIGZpbGxPcGFjaXR5ID0wLjgsCiAgICAgICAgICAgIGNvbG9yID0gfnBhbDIoUGVyY2VudGlsZSksCiAgICAgICAgICAgIGhpZ2hsaWdodE9wdGlvbnMgPSBoaWdobGlnaHRPcHRpb25zKGNvbG9yID0gImJsYWNrIiwgd2VpZ2h0ID0gMiwKICAgICAgYnJpbmdUb0Zyb250ID0gVFJVRSkpICU+JSAKaGlkZUdyb3VwKCIyMDA2IikgJT4lIAogIAphZGRQb2x5Z29ucyhkYXRhPWV4YW1wbGVzaGFwZXMyW2V4YW1wbGVzaGFwZXMyJHllYXIgPT0gMjAwOSwgXSwgCiAgICAgICAgICAgIHdlaWdodCA9IDIsIAogICAgICAgICAgICBsYWJlbCA9IGxpc3RsaXN0bGlzdFsxNToyMV0sCiAgICAgICAgICAgIGdyb3VwID0gIjIwMDkiLAogICAgICAgICAgICBmaWxsT3BhY2l0eSA9MC44LAogICAgICAgICAgICBjb2xvciA9IH5wYWwyKFBlcmNlbnRpbGUpLAogICAgICAgICAgICBoaWdobGlnaHRPcHRpb25zID0gaGlnaGxpZ2h0T3B0aW9ucyhjb2xvciA9ICJibGFjayIsIHdlaWdodCA9IDIsCiAgICAgIGJyaW5nVG9Gcm9udCA9IFRSVUUpKSAlPiUgCmhpZGVHcm91cCgiMjAwOSIpICU+JSAKICAKYWRkUG9seWdvbnMoZGF0YT1leGFtcGxlc2hhcGVzMltleGFtcGxlc2hhcGVzMiR5ZWFyID09IDIwMTIsIF0sIAogICAgICAgICAgICB3ZWlnaHQgPSAyLCAKICAgICAgICAgICAgbGFiZWwgPSBsaXN0bGlzdGxpc3RbODoxNF0sCiAgICAgICAgICAgIGdyb3VwID0gIjIwMTIiLAogICAgICAgICAgICBmaWxsT3BhY2l0eSA9MC44LAogICAgICAgICAgICBjb2xvciA9IH5wYWwyKFBlcmNlbnRpbGUpLAogICAgICAgICAgICBoaWdobGlnaHRPcHRpb25zID0gaGlnaGxpZ2h0T3B0aW9ucyhjb2xvciA9ICJibGFjayIsIHdlaWdodCA9IDIsCiAgICAgIGJyaW5nVG9Gcm9udCA9IFRSVUUpKSAlPiUgCmhpZGVHcm91cCgiMjAxMiIpICU+JSAKCmFkZFBvbHlnb25zKGRhdGE9ZXhhbXBsZXNoYXBlczJbZXhhbXBsZXNoYXBlczIkeWVhciA9PSAyMDE2LCBdLCAKICAgICAgICAgICAgd2VpZ2h0ID0gMiwgCiAgICAgICAgICAgIGxhYmVsID0gbGlzdGxpc3RsaXN0WzE6N10sCiAgICAgICAgICAgIGdyb3VwID0gIjIwMTYiLAogICAgICAgICAgICBmaWxsT3BhY2l0eSA9MC44LAogICAgICAgICAgICBjb2xvciA9IH5wYWwyKFBlcmNlbnRpbGUpLAogICAgICAgICAgICBoaWdobGlnaHRPcHRpb25zID0gaGlnaGxpZ2h0T3B0aW9ucyhjb2xvciA9ICJibGFjayIsIHdlaWdodCA9IDIsCiAgICAgIGJyaW5nVG9Gcm9udCA9IFRSVUUpKSAlPiUgCmhpZGVHcm91cCgiMjAxNiIpICU+JSAKICAKI2NsaW5pY2Nvb3JkaW5hdGVzCmFkZE1hcmtlcnMoCiAgICBsbmcgPSBjbGluaWNjb29yZGluYXRlcyRsb25naXR1ZGUsIGxhdCA9IGNsaW5pY2Nvb3JkaW5hdGVzJGxhdGl0dWRlLAogICAgbGFiZWwgPSBjbGluaWNjb29yZGluYXRlcyRYLAogICAgbGFiZWxPcHRpb25zID0gbGFiZWxPcHRpb25zKG5vSGlkZSA9IEYpLCBncm91cCA9IGNsaW5pY2Nvb3JkaW5hdGVzJFgpICU+JQogIGhpZGVHcm91cChjbGluaWNjb29yZGluYXRlcyRYKSAlPiUgICAKCmFkZExlZ2VuZCgiYm90dG9tbGVmdCIsIHBhbCA9IHBhbDIsIHZhbHVlcyA9IGV4YW1wbGVzaGFwZXMyJFBlcmNlbnRpbGUsCiAgICB0aXRsZSA9ICJTSU1EIFBlcmNlbnRpbGUiLAogICAgbGFiRm9ybWF0ID0gbGFiZWxGb3JtYXQoc3VmZml4ID0gIiUiKSwKICAgIG9wYWNpdHkgPSAxCiAgKSAgJT4lICAKCiNMYXllcnMgY29udHJvbAphZGRMYXllcnNDb250cm9sKAogICAgYmFzZUdyb3VwcyA9IGMoIjIwMDQiLCAiMjAwNiIsICIyMDA5IiwgIjIwMTIiLCAiMjAxNiIsICJOb3RoaW5nIiksCiAgICBvdmVybGF5R3JvdXBzID0gYyhjbGluaWNjb29yZGluYXRlcyRYKSwKICAgIG9wdGlvbnMgPSBsYXllcnNDb250cm9sT3B0aW9ucyhjb2xsYXBzZWQgPSBUUlVFKQogICkKYGBgCgojTWFwNCBBcnJhbiB2cy4gU2NvdGxhbmQKQmVhdXRpZnVsIG1hcCwgYnV0IEkgaGF2ZSB0byBsZWF2ZSB0aGUgbGFwdG9wIHJ1bm5pbmcgb3Zlcm5pZ2h0IHRvIGNvbXBpbGUgaXQuCmBgYHtyIGV2YWw9RkFMU0V9CiNJbXBvcnQgVUsgZGF0YQpEWkJvdW5kYXJpZXMyMDE2IDwtIHJlYWRfc2YoIi4uL2FsbGRhdGEvU0dfU0lNRF8yMDE2IikKU2NvdGxhbmQyMDE2IDwtIGFzKERaQm91bmRhcmllczIwMTYsICJTcGF0aWFsIikgJT4lCnNwVHJhbnNmb3JtKENSUygiK3Byb2o9bG9uZ2xhdCArZGF0dW09V0dTODQiKSkKCkRaQm91bmRhcmllczIwMTIgPC0gcmVhZF9zZigiLi4vYWxsZGF0YS9TR19TSU1EXzIwMTIiKQpTY290bGFuZDIwMTIgPC0gYXMoRFpCb3VuZGFyaWVzMjAxMiwgIlNwYXRpYWwiKSAlPiUKc3BUcmFuc2Zvcm0oQ1JTKCIrcHJvaj1sb25nbGF0ICtkYXR1bT1XR1M4NCIpKQoKRFpCb3VuZGFyaWVzMjAwOSA8LSByZWFkX3NmKCIuLi9hbGxkYXRhL1NHX1NJTURfMjAwOSIpClNjb3RsYW5kMjAwOSA8LSBhcyhEWkJvdW5kYXJpZXMyMDA5LCAiU3BhdGlhbCIpICU+JQpzcFRyYW5zZm9ybShDUlMoIitwcm9qPWxvbmdsYXQgK2RhdHVtPVdHUzg0IikpCgpEWkJvdW5kYXJpZXMyMDA2IDwtIHJlYWRfc2YoIi4uL2FsbGRhdGEvU0dfU0lNRF8yMDA2IikKU2NvdGxhbmQyMDA2IDwtIGFzKERaQm91bmRhcmllczIwMDYsICJTcGF0aWFsIikgJT4lCnNwVHJhbnNmb3JtKENSUygiK3Byb2o9bG9uZ2xhdCArZGF0dW09V0dTODQiKSkKCkRaQm91bmRhcmllczIwMDQgPC0gcmVhZF9zZigiLi4vYWxsZGF0YS9TR19TSU1EXzIwMDQiKQpTY290bGFuZDIwMDQgPC0gYXMoRFpCb3VuZGFyaWVzMjAwNCwgIlNwYXRpYWwiKSAlPiUKc3BUcmFuc2Zvcm0oQ1JTKCIrcHJvaj1sb25nbGF0ICtkYXR1bT1XR1M4NCIpKQoKI0NvbG91ciBQYWxhdGUKcGFsMiA8LSBjb2xvck51bWVyaWMoCiAgcGFsZXR0ZSA9ICJ2aXJpZGlzIiwKICBkb21haW4gPSAwOjEwMCkKCmxlYWZsZXQoKSAlPiUgCiAgYWRkVGlsZXMoKSAlPiUgCiAgc2V0VmlldygtNS4yMjc2ODAsIDU1LjU4MjMzOCwgem9vbSA9IDEwKSAlPiUgCgphZGRQb2x5Z29ucyhkYXRhPWV4YW1wbGVzaGFwZXMyW2V4YW1wbGVzaGFwZXMyJHllYXIgPT0gMjAwNCwgXSwgCiAgICAgICAgICAgIHdlaWdodCA9IDIsIAogICAgICAgICAgICBsYWJlbCA9IGxpc3RsaXN0bGlzdFsyOTozNV0sCiAgICAgICAgICAgIGdyb3VwID0gIjIwMDQiLAogICAgICAgICAgICBmaWxsT3BhY2l0eSA9MC44LAogICAgICAgICAgICBjb2xvciA9IH5wYWwyKFBlcmNlbnRpbGUpLAogICAgICAgICAgICBoaWdobGlnaHRPcHRpb25zID0gaGlnaGxpZ2h0T3B0aW9ucyhjb2xvciA9ICJibGFjayIsIHdlaWdodCA9IDIsCiAgICAgIGJyaW5nVG9Gcm9udCA9IFRSVUUpKSAlPiUgCmhpZGVHcm91cCgiMjAwNCIpICU+JSAKICAKYWRkUG9seWdvbnMoZGF0YT1TY290bGFuZDIwMDQsIAogICAgICAgICAgICB3ZWlnaHQgPSAyLCAKICAgICAgICAgICAgZ3JvdXAgPSAiU2NvdGxhbmQgMjAwNCIsCiAgICAgICAgICAgIGZpbGxPcGFjaXR5ID0wLjgsCiAgICAgICAgICAgIGNvbG9yID0gfnBhbDIoUGVyY2VudGlsZSksCiAgICAgICAgICAgIGhpZ2hsaWdodE9wdGlvbnMgPSBoaWdobGlnaHRPcHRpb25zKGNvbG9yID0gImJsYWNrIiwgd2VpZ2h0ID0gMiwKICAgICAgYnJpbmdUb0Zyb250ID0gVFJVRSkpICU+JSAKaGlkZUdyb3VwKCJTY290bGFuZCAyMDA0IikgJT4lIAogIAphZGRQb2x5Z29ucyhkYXRhPWV4YW1wbGVzaGFwZXMyW2V4YW1wbGVzaGFwZXMyJHllYXIgPT0gMjAwNiwgXSwgCiAgICAgICAgICAgIHdlaWdodCA9IDIsIAogICAgICAgICAgICBsYWJlbCA9IGxpc3RsaXN0bGlzdFsyMjoyOF0sCiAgICAgICAgICAgIGdyb3VwID0gIjIwMDYiLAogICAgICAgICAgICBmaWxsT3BhY2l0eSA9MC44LAogICAgICAgICAgICBjb2xvciA9IH5wYWwyKFBlcmNlbnRpbGUpLAogICAgICAgICAgICBoaWdobGlnaHRPcHRpb25zID0gaGlnaGxpZ2h0T3B0aW9ucyhjb2xvciA9ICJibGFjayIsIHdlaWdodCA9IDIsCiAgICAgIGJyaW5nVG9Gcm9udCA9IFRSVUUpKSAlPiUgCmhpZGVHcm91cCgiMjAwNiIpICU+JSAKCmFkZFBvbHlnb25zKGRhdGE9U2NvdGxhbmQyMDA2LCAKICAgICAgICAgICAgd2VpZ2h0ID0gMiwgCiAgICAgICAgICAgIGdyb3VwID0gIlNjb3RsYW5kIDIwMDYiLAogICAgICAgICAgICBmaWxsT3BhY2l0eSA9MC44LAogICAgICAgICAgICBjb2xvciA9IH5wYWwyKFBlcmNlbnRpbGUpLAogICAgICAgICAgICBoaWdobGlnaHRPcHRpb25zID0gaGlnaGxpZ2h0T3B0aW9ucyhjb2xvciA9ICJibGFjayIsIHdlaWdodCA9IDIsCiAgICAgIGJyaW5nVG9Gcm9udCA9IFRSVUUpKSAlPiUgCmhpZGVHcm91cCgiU2NvdGxhbmQgMjAwNiIpICU+JSAKICAKYWRkUG9seWdvbnMoZGF0YT1leGFtcGxlc2hhcGVzMltleGFtcGxlc2hhcGVzMiR5ZWFyID09IDIwMDksIF0sIAogICAgICAgICAgICB3ZWlnaHQgPSAyLCAKICAgICAgICAgICAgbGFiZWwgPSBsaXN0bGlzdGxpc3RbMTU6MjFdLAogICAgICAgICAgICBncm91cCA9ICIyMDA5IiwKICAgICAgICAgICAgZmlsbE9wYWNpdHkgPTAuOCwKICAgICAgICAgICAgY29sb3IgPSB+cGFsMihQZXJjZW50aWxlKSwKICAgICAgICAgICAgaGlnaGxpZ2h0T3B0aW9ucyA9IGhpZ2hsaWdodE9wdGlvbnMoY29sb3IgPSAiYmxhY2siLCB3ZWlnaHQgPSAyLAogICAgICBicmluZ1RvRnJvbnQgPSBUUlVFKSkgJT4lIApoaWRlR3JvdXAoIjIwMDkiKSAlPiUgCgphZGRQb2x5Z29ucyhkYXRhPVNjb3RsYW5kMjAwOSwgCiAgICAgICAgICAgIHdlaWdodCA9IDIsIAogICAgICAgICAgICBncm91cCA9ICJTY290bGFuZCAyMDA5IiwKICAgICAgICAgICAgZmlsbE9wYWNpdHkgPTAuOCwKICAgICAgICAgICAgY29sb3IgPSB+cGFsMihQZXJjZW50aWxlKSwKICAgICAgICAgICAgaGlnaGxpZ2h0T3B0aW9ucyA9IGhpZ2hsaWdodE9wdGlvbnMoY29sb3IgPSAiYmxhY2siLCB3ZWlnaHQgPSAyLAogICAgICBicmluZ1RvRnJvbnQgPSBUUlVFKSkgJT4lIApoaWRlR3JvdXAoIlNjb3RsYW5kIDIwMDkiKSAlPiUgCiAgCmFkZFBvbHlnb25zKGRhdGE9ZXhhbXBsZXNoYXBlczJbZXhhbXBsZXNoYXBlczIkeWVhciA9PSAyMDEyLCBdLCAKICAgICAgICAgICAgd2VpZ2h0ID0gMiwgCiAgICAgICAgICAgIGxhYmVsID0gbGlzdGxpc3RsaXN0Wzg6MTRdLAogICAgICAgICAgICBncm91cCA9ICIyMDEyIiwKICAgICAgICAgICAgZmlsbE9wYWNpdHkgPTAuOCwKICAgICAgICAgICAgY29sb3IgPSB+cGFsMihQZXJjZW50aWxlKSwKICAgICAgICAgICAgaGlnaGxpZ2h0T3B0aW9ucyA9IGhpZ2hsaWdodE9wdGlvbnMoY29sb3IgPSAiYmxhY2siLCB3ZWlnaHQgPSAyLAogICAgICBicmluZ1RvRnJvbnQgPSBUUlVFKSkgJT4lIApoaWRlR3JvdXAoIjIwMTIiKSAlPiUgCiAgCmFkZFBvbHlnb25zKGRhdGE9U2NvdGxhbmQyMDEyLCAKICAgICAgICAgICAgd2VpZ2h0ID0gMiwgCiAgICAgICAgICAgIGdyb3VwID0gIlNjb3RsYW5kIDIwMTIiLAogICAgICAgICAgICBmaWxsT3BhY2l0eSA9MC44LAogICAgICAgICAgICBjb2xvciA9IH5wYWwyKFBlcmNlbnRpbGUpLAogICAgICAgICAgICBoaWdobGlnaHRPcHRpb25zID0gaGlnaGxpZ2h0T3B0aW9ucyhjb2xvciA9ICJibGFjayIsIHdlaWdodCA9IDIsCiAgICAgIGJyaW5nVG9Gcm9udCA9IFRSVUUpKSAlPiUgCmhpZGVHcm91cCgiU2NvdGxhbmQgMjAxMiIpICU+JSAKCmFkZFBvbHlnb25zKGRhdGE9ZXhhbXBsZXNoYXBlczJbZXhhbXBsZXNoYXBlczIkeWVhciA9PSAyMDE2LCBdLCAKICAgICAgICAgICAgd2VpZ2h0ID0gMiwgCiAgICAgICAgICAgIGxhYmVsID0gbGlzdGxpc3RsaXN0WzE6N10sCiAgICAgICAgICAgIGdyb3VwID0gIjIwMTYiLAogICAgICAgICAgICBmaWxsT3BhY2l0eSA9MC44LAogICAgICAgICAgICBjb2xvciA9IH5wYWwyKFBlcmNlbnRpbGUpLAogICAgICAgICAgICBoaWdobGlnaHRPcHRpb25zID0gaGlnaGxpZ2h0T3B0aW9ucyhjb2xvciA9ICJibGFjayIsIHdlaWdodCA9IDIsCiAgICAgIGJyaW5nVG9Gcm9udCA9IFRSVUUpKSAlPiUgCmhpZGVHcm91cCgiMjAxNiIpICU+JSAKCmFkZFBvbHlnb25zKGRhdGE9U2NvdGxhbmQyMDEyLCAKICAgICAgICAgICAgd2VpZ2h0ID0gMiwgCiAgICAgICAgICAgIGdyb3VwID0gIlNjb3RsYW5kIDIwMTYiLAogICAgICAgICAgICBmaWxsT3BhY2l0eSA9MC44LAogICAgICAgICAgICBjb2xvciA9IH5wYWwyKFBlcmNlbnRpbGUpLAogICAgICAgICAgICBoaWdobGlnaHRPcHRpb25zID0gaGlnaGxpZ2h0T3B0aW9ucyhjb2xvciA9ICJibGFjayIsIHdlaWdodCA9IDIsCiAgICAgIGJyaW5nVG9Gcm9udCA9IFRSVUUpKSAlPiUgCmhpZGVHcm91cCgiU2NvdGxhbmQgMjAxNiIpICU+JSAKICAKYWRkTWFya2VycygKICAgIGxuZyA9IGNsaW5pY2Nvb3JkaW5hdGVzJGxvbmdpdHVkZSwgbGF0ID0gY2xpbmljY29vcmRpbmF0ZXMkbGF0aXR1ZGUsCiAgICBsYWJlbCA9IGNsaW5pY2Nvb3JkaW5hdGVzJFgsCiAgICBsYWJlbE9wdGlvbnMgPSBsYWJlbE9wdGlvbnMobm9IaWRlID0gRiksIGdyb3VwID0gY2xpbmljY29vcmRpbmF0ZXMkWCkgJT4lCiAgaGlkZUdyb3VwKGNsaW5pY2Nvb3JkaW5hdGVzJFgpICU+JSAgIAoKYWRkTGVnZW5kKCJib3R0b21sZWZ0IiwgcGFsID0gcGFsMiwgdmFsdWVzID0gZXhhbXBsZXNoYXBlczIkUGVyY2VudGlsZSwKICAgIHRpdGxlID0gIlNJTUQgUGVyY2VudGlsZSIsCiAgICBsYWJGb3JtYXQgPSBsYWJlbEZvcm1hdChzdWZmaXggPSAiJSIpLAogICAgb3BhY2l0eSA9IDEKICApICAlPiUgIAoKYWRkTGF5ZXJzQ29udHJvbCgKICAgIGJhc2VHcm91cHMgPSBjKCIyMDA0IiwgIlNjb3RsYW5kIDIwMDQiLCAiMjAwNiIsICJTY290bGFuZCAyMDA2IiwgIjIwMDkiLCAiU2NvdGxhbmQgMjAwOSIsICIyMDEyIiwgIlNjb3RsYW5kIDIwMTIiLCAiMjAxNiIsICJTY290bGFuZCAyMDE2IiwgIk5vdGhpbmciKSwKICAgIG92ZXJsYXlHcm91cHMgPSBjKGNsaW5pY2Nvb3JkaW5hdGVzJFgpLAogICAgb3B0aW9ucyA9IGxheWVyc0NvbnRyb2xPcHRpb25zKGNvbGxhcHNlZCA9IFRSVUUpCiAgKQpgYGAKCiFbTWFwNF0oUnBsb3RNYXA0LnBuZykKCiNNYXA1CkknbGwgY29udGludWUgdGhpcyBvbiBhIG5ldyBkb2N1bWVudCBzbyBJIGNhbiBrbml0IGl0IHRvIGFuIGh0bWwgd2Vic2l0ZS4gCgpbTWFwNS5dKE1hcDV2aWV3Lmh0bWwpCgpbTWFwNSBDb2RlLl0oTWFwNV9Db2RlLmh0bWwpCgpCdXQgdGhlIGRldmVsb3BtZW50IGlzIHRoYXQgSSd2ZSB1c2VkIGludGVyc2VjdCgpIG9uIGVhY2ggZmlsdGVyZWQgJ1NHX1NJTURfLi4uJyB0byBjcmVhdGUgdGhlICdzaGFyZWR2YXJpYWJsZXMnIHZlY3Rvciwgc28gSSB3YXMgYWJsZSB0byBjcmVhdGUgYSBuZXcgZGF0YWZyYW1lIG9mIGV2ZXJ5IHllYXIgd2l0aCBvbmx5IHNoYXJlZCB2YXJpYWJsZXMsIHJhdGhlciB0aGFuIHBlcmNlbnRpbGUgYWxvbmUgIHdoaWNoIEkgb3JpZ2luYWxseSB1c2VkIGFzIGFuIGV4YW1wbGUgdG8gcHJhY3RpY2UgdGhlIG1hcHMgb24gKG15IHByZXZpb3VzIHZlcnNpb24gb2YgJ2FycmFuc2ltZCcpLgpUaGUgbmV3ICdhcnJhblNJTUQnIGNhbiB0aGVuIGhhdmUgYSB2ZXJzaW9uIG9mIG1hcDMgZm9yIGVhY2ggc2hhcmVkIHZhcmlhYmxlLgoKW0dvIGJhY2suXShodHRwczovL2Zlcmd1c3RheWxvci5naXRodWIuaW8vQXJyYW4pCgo=